package com.lifang.framework.aop.framework.support;

import cn.hutool.core.collection.CollectionUtil;
import com.lifang.framework.aop.MethodMatcher;
import com.lifang.framework.aop.aspectj.AbstractAspectJAdvice;
import com.lifang.framework.aop.framework.InterceptorAndDynamicMethodMatcher;
import com.lifang.framework.aop.framework.ProxyFactory;
import com.lifang.framework.aop.framework.SingletonTargetSource;
import org.aopalliance.aop.Advice;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class DefaultAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {

    /**
     * 如果有必要，包装Bean为代理对象
     */
    @Override
    protected Object wrapIfNecessary(Object bean, String beanName, List<Advice> adviceList) {
        if (CollectionUtil.isNotEmpty(adviceList)) {
            List<Advice> availableAdvice = new ArrayList<>();
            for (Advice advice : adviceList) {
                if (advice instanceof AbstractAspectJAdvice) {
                    AbstractAspectJAdvice aspectJAdvice = (AbstractAspectJAdvice) advice;
                    if (aspectJAdvice.getPointcut().getClassFilter().matches(bean.getClass())) {
                        availableAdvice.add(advice);
                    }
                }
            }
            if (CollectionUtil.isNotEmpty(availableAdvice)) {
                availableAdvice = availableAdvice.stream().
                        sorted(Comparator.comparing(item -> ((AbstractAspectJAdvice) item).getOrder())).collect(Collectors.toList());
                SingletonTargetSource targetSource = new SingletonTargetSource(bean, beanName, getBeanFactory());
                AdvisedSupport advisedSupport = new AdvisedSupport();
                advisedSupport.setTargetSource(targetSource);
                for (Advice advice : availableAdvice) {
                    AbstractAspectJAdvice aspectJAdvice = (AbstractAspectJAdvice) advice;
                    MethodMatcher methodMatcher = aspectJAdvice.getPointcut().getMethodMatcher();
                    aspectJAdvice.setAspectjInstance(getBeanFactory().getBean(aspectJAdvice.getDeclaringClass()));
                    advisedSupport.addMethodInterceptor(new InterceptorAndDynamicMethodMatcher(methodMatcher, aspectJAdvice));
                }
                return new ProxyFactory(advisedSupport).getProxy();
            } else {
                this.advisedBeans.put(beanName, Boolean.FALSE);
            }
        }
        return bean;
    }
}
